"""
Content Generation Service
内容生成服务 - 内容创建、参数验证、任务调度
"""

import uuid
import json
from typing import Optional, Dict, Any, List
from datetime import datetime, timedelta

from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, and_, or_, func
from sqlalchemy.orm import selectinload
import structlog

from ..models.user import User
from ..models.creation_request import CreationRequest, ContentType, RequestStatus, Priority
from ..models.generated_content import GeneratedContent, ContentStatus
from ..models.task_queue import TaskQueue, TaskType, TaskStatus, TaskPriority
from ..core.database import DatabaseSession
from ..core.config import settings
from ..core.exceptions import (
    ValidationError,
    UserNotFoundError,
    ContentGenerationError,
    ContentValidationError,
    AIModelNotAvailableError,
    RateLimitExceededError,
)
from .task_queue_service import TaskQueueService

# 配置结构化日志
logger = structlog.get_logger(__name__)


class ContentGenerationService:
    """内容生成服务类"""

    def __init__(self, db_session: DatabaseSession, task_queue_service: TaskQueueService):
        self.db_session = db_session
        self.task_queue_service = task_queue_service

    async def create_content_request(
        self,
        user: User,
        content_type: str,
        prompt: str,
        **kwargs
    ) -> CreationRequest:
        """
        创建内容生成请求

        Args:
            user: 用户对象
            content_type: 内容类型 (image, video, audio, text)
            prompt: 生成提示词
            **kwargs: 其他参数

        Returns:
            CreationRequest: 创建请求对象

        Raises:
            ValidationError: 参数验证失败
            RateLimitExceededError: 超出速率限制
            ContentGenerationError: 内容生成失败
        """
        logger.info("创建内容生成请求", 
                   user_id=str(user.id), 
                   content_type=content_type, 
                   prompt_length=len(prompt))

        # 验证用户权限和限制
        await self._validate_user_permissions(user)
        
        # 验证输入参数
        await self._validate_creation_params(content_type, prompt, **kwargs)

        # 检查速率限制
        await self._check_rate_limit(user)

        # 检查存储配额
        await self._check_storage_quota(user)

        async with self.db_session as session:
            # 创建生成请求
            creation_request = CreationRequest(
                user_id=user.id,
                content_type=content_type,
                prompt=prompt,
                **kwargs
            )

            # 设置默认值
            self._set_default_values(creation_request, user)

            session.add(creation_request)
            await session.flush()

            # 提交到任务队列
            await self._submit_to_task_queue(session, creation_request)

            await session.commit()
            await session.refresh(creation_request)

            logger.info("内容生成请求创建成功", 
                       request_id=str(creation_request.id), 
                       user_id=str(user.id))
            return creation_request

    async def get_content_request(self, request_id: uuid.UUID, user: User) -> Optional[CreationRequest]:
        """
        获取内容生成请求

        Args:
            request_id: 请求ID
            user: 用户对象

        Returns:
            Optional[CreationRequest]: 请求对象，不存在返回None

        Raises:
            PermissionDeniedError: 无权访问
        """
        async with self.db_session as session:
            result = await session.execute(
                select(CreationRequest)
                .where(CreationRequest.id == request_id)
                .options(
                    selectinload(CreationRequest.user),
                    selectinload(CreationRequest.generated_contents)
                )
            )
            request = result.scalar_one_or_none()

            if not request:
                return None

            # 检查权限
            if request.user_id != user.id and not user.is_admin:
                from ..core.exceptions import PermissionDeniedError
                raise PermissionDeniedError("无权访问此请求")

            return request

    async def get_user_content_requests(
        self,
        user: User,
        status: Optional[str] = None,
        content_type: Optional[str] = None,
        skip: int = 0,
        limit: int = 50
    ) -> List[CreationRequest]:
        """
        获取用户的内容生成请求列表

        Args:
            user: 用户对象
            status: 状态过滤
            content_type: 内容类型过滤
            skip: 跳过数量
            limit: 限制数量

        Returns:
            List[CreationRequest]: 请求列表
        """
        async with self.db_session as session:
            query = select(CreationRequest).where(CreationRequest.user_id == user.id)

            # 应用过滤条件
            if status:
                query = query.where(CreationRequest.status == status)
            if content_type:
                query = query.where(CreationRequest.content_type == content_type)

            # 排序和分页
            query = query.order_by(CreationRequest.created_at.desc()).offset(skip).limit(limit)

            result = await session.execute(query)
            return result.scalars().all()

    async def cancel_content_request(
        self,
        request_id: uuid.UUID,
        user: User
    ) -> bool:
        """
        取消内容生成请求

        Args:
            request_id: 请求ID
            user: 用户对象

        Returns:
            bool: 是否成功取消

        Raises:
            PermissionDeniedError: 无权操作
            ContentGenerationError: 请求无法取消
        """
        logger.info("取消内容生成请求", request_id=str(request_id), user_id=str(user.id))

        async with self.db_session as session:
            result = await session.execute(
                select(CreationRequest)
                .where(CreationRequest.id == request_id)
                .options(selectinload(CreationRequest.task_queues))
            )
            request = result.scalar_one_or_none()

            if not request:
                return False

            # 检查权限
            if request.user_id != user.id and not user.is_admin:
                from ..core.exceptions import PermissionDeniedError
                raise PermissionDeniedError("无权取消此请求")

            # 检查是否可以取消
            if request.status not in [RequestStatus.PENDING, RequestStatus.PROCESSING]:
                raise ContentGenerationError(f"当前状态为 {request.status}，无法取消")

            # 取消相关任务
            for task in request.task_queues:
                if task.status in [TaskStatus.PENDING, TaskStatus.QUEUED, TaskStatus.PROCESSING]:
                    await self.task_queue_service.cancel_task(task.task_id)

            # 更新请求状态
            request.status = RequestStatus.CANCELLED
            request.error_message = "用户主动取消"
            request.completed_at = datetime.utcnow()

            await session.commit()

            logger.info("内容生成请求取消成功", request_id=str(request_id))
            return True

    async def retry_content_request(
        self,
        request_id: uuid.UUID,
        user: User
    ) -> Optional[CreationRequest]:
        """
        重试内容生成请求

        Args:
            request_id: 请求ID
            user: 用户对象

        Returns:
            Optional[CreationRequest]: 重试后的请求对象

        Raises:
            PermissionDeniedError: 无权操作
            ContentGenerationError: 请求无法重试
        """
        logger.info("重试内容生成请求", request_id=str(request_id), user_id=str(user.id))

        async with self.db_session as session:
            result = await session.execute(
                select(CreationRequest)
                .where(CreationRequest.id == request_id)
                .options(selectinload(CreationRequest.user))
            )
            request = result.scalar_one_or_none()

            if not request:
                return None

            # 检查权限
            if request.user_id != user.id and not user.is_admin:
                from ..core.exceptions import PermissionDeniedError
                raise PermissionDeniedError("无权重试此请求")

            # 检查是否可以重试
            if not request.can_retry():
                raise ContentGenerationError(f"当前状态为 {request.status}，无法重试")

            # 重置请求状态
            request.status = RequestStatus.PENDING
            request.progress = 0
            request.error_message = None
            request.error_code = None
            request.retry_count = (request.retry_count or 0) + 1
            request.started_at = None
            request.completed_at = None

            # 重新提交到任务队列
            await self._submit_to_task_queue(session, request)

            await session.commit()
            await session.refresh(request)

            logger.info("内容生成请求重试成功", request_id=str(request_id))
            return request

    async def get_content_request_statistics(self, user: User) -> Dict[str, Any]:
        """
        获取用户的内容生成请求统计

        Args:
            user: 用户对象

        Returns:
            Dict[str, Any]: 统计信息
        """
        async with self.db_session as session:
            # 总体统计
            total_result = await session.execute(
                select(
                    func.count(CreationRequest.id),
                    func.count(CreationRequest.id).filter(CreationRequest.status == RequestStatus.COMPLETED),
                    func.count(CreationRequest.id).filter(CreationRequest.status == RequestStatus.FAILED),
                    func.count(CreationRequest.id).filter(CreationRequest.status == RequestStatus.PROCESSING),
                    func.count(CreationRequest.id).filter(CreationRequest.status == RequestStatus.PENDING)
                ).where(CreationRequest.user_id == user.id)
            )
            total, completed, failed, processing, pending = total_result.first()

            # 按内容类型统计
            by_type_result = await session.execute(
                select(
                    CreationRequest.content_type,
                    func.count(CreationRequest.id)
                )
                .where(CreationRequest.user_id == user.id)
                .group_by(CreationRequest.content_type)
            )
            by_type = dict(by_type_result.all())

            # 最近活动
            recent_result = await session.execute(
                select(CreationRequest)
                .where(CreationRequest.user_id == user.id)
                .order_by(CreationRequest.created_at.desc())
                .limit(5)
            )
            recent_requests = recent_result.scalars().all()

            return {
                "user_id": str(user.id),
                "total_requests": total or 0,
                "completed_requests": completed or 0,
                "failed_requests": failed or 0,
                "processing_requests": processing or 0,
                "pending_requests": pending or 0,
                "success_rate": (completed / total * 100) if total > 0 else 0,
                "by_content_type": by_type,
                "recent_requests": [
                    {
                        "id": str(req.id),
                        "content_type": req.content_type,
                        "status": req.status,
                        "created_at": req.created_at.isoformat() if req.created_at else None,
                        "title": req.title,
                        "progress": req.progress
                    }
                    for req in recent_requests
                ]
            }

    async def validate_generation_parameters(
        self,
        content_type: str,
        parameters: Dict[str, Any]
    ) -> Dict[str, Any]:
        """
        验证生成参数

        Args:
            content_type: 内容类型
            parameters: 参数字典

        Returns:
            Dict[str, Any]: 验证后的参数

        Raises:
            ContentValidationError: 参数验证失败
        """
        validated_params = {}

        # 通用参数验证
        if "quality" in parameters:
            quality = parameters["quality"]
            if quality not in ["low", "medium", "high", "ultra"]:
                raise ContentValidationError(f"无效的质量设置: {quality}")
            validated_params["quality"] = quality

        if "style" in parameters:
            style = parameters["style"]
            if len(style) > 100:
                raise ContentValidationError("风格描述过长，最大100字符")
            validated_params["style"] = style

        # 内容类型特定验证
        if content_type == "image":
            validated_params.update(self._validate_image_parameters(parameters))
        elif content_type == "video":
            validated_params.update(self._validate_video_parameters(parameters))
        elif content_type == "audio":
            validated_params.update(self._validate_audio_parameters(parameters))
        elif content_type == "text":
            validated_params.update(self._validate_text_parameters(parameters))
        else:
            raise ContentValidationError(f"不支持的内容类型: {content_type}")

        return validated_params

    # 私有辅助方法

    async def _validate_user_permissions(self, user: User) -> None:
        """验证用户权限"""
        if not user.is_active:
            raise ContentGenerationError("用户账户非活跃状态")
        
        if user.storage_usage_percent >= 100:
            raise ContentGenerationError("存储空间已满，无法创建新内容")

    async def _validate_creation_params(
        self,
        content_type: str,
        prompt: str,
        **kwargs
    ) -> None:
        """验证创建参数"""
        # 验证内容类型
        valid_content_types = ["image", "video", "audio", "text"]
        if content_type not in valid_content_types:
            raise ValidationError(f"无效的内容类型: {content_type}")

        # 验证提示词
        if not prompt or len(prompt.strip()) == 0:
            raise ValidationError("提示词不能为空")
        
        if len(prompt) > 5000:
            raise ValidationError("提示词过长，最大5000字符")

        # 验证负面提示词
        negative_prompt = kwargs.get("negative_prompt")
        if negative_prompt and len(negative_prompt) > 5000:
            raise ValidationError("负面提示词过长，最大5000字符")

        # 验证AI提供商
        ai_provider = kwargs.get("ai_provider", "doubao")
        valid_providers = ["doubao", "ali", "openai"]
        if ai_provider not in valid_providers:
            raise ValidationError(f"无效的AI提供商: {ai_provider}")

        # 验证批量大小
        batch_size = kwargs.get("batch_size", 1)
        if not isinstance(batch_size, int) or batch_size < 1 or batch_size > 10:
            raise ValidationError("批量大小必须在1-10之间")

        # 验证变体数量
        variations = kwargs.get("variations", 1)
        if not isinstance(variations, int) or variations < 1 or variations > 5:
            raise ValidationError("变体数量必须在1-5之间")

    async def _check_rate_limit(self, user: User) -> None:
        """检查速率限制"""
        # TODO: 实现完整的速率限制逻辑
        # 这里可以实现基于用户级别的速率限制
        pass

    async def _check_storage_quota(self, user: User) -> None:
        """检查存储配额"""
        if user.storage_usage_percent >= 100:
            raise RateLimitExceededError("存储空间已满")

    def _set_default_values(self, request: CreationRequest, user: User) -> None:
        """设置默认值"""
        # 设置优先级
        if not request.priority:
            request.priority = Priority.NORMAL

        # 设置AI提供商
        if not request.ai_provider:
            request.ai_provider = user.settings.default_ai_provider if user.settings else "doubao"

        # 设置质量
        if not request.quality:
            request.quality = user.settings.default_quality if user.settings else "high"

        # 设置内容特定默认值
        if request.content_type == "image":
            if not request.width:
                request.width = 1024  # 默认宽度
            if not request.height:
                request.height = 1024  # 默认高度
        elif request.content_type == "video":
            if not request.duration:
                request.duration = user.settings.default_video_duration if user.settings else 5
        elif request.content_type == "audio":
            if not request.duration:
                request.duration = user.settings.default_audio_duration if user.settings else 30

        # 设置过期时间
        if not request.expires_at:
            request.expires_at = datetime.utcnow() + timedelta(hours=24)

    def _validate_image_parameters(self, parameters: Dict[str, Any]) -> Dict[str, Any]:
        """验证图片参数"""
        validated = {}

        # 验证尺寸
        if "width" in parameters:
            width = parameters["width"]
            if not isinstance(width, int) or width < 64 or width > 4096:
                raise ContentValidationError("图片宽度必须在64-4096像素之间")
            validated["width"] = width

        if "height" in parameters:
            height = parameters["height"]
            if not isinstance(height, int) or height < 64 or height > 4096:
                raise ContentValidationError("图片高度必须在64-4096像素之间")
            validated["height"] = height

        # 验证引导系数
        if "guidance_scale" in parameters:
            guidance_scale = parameters["guidance_scale"]
            if not isinstance(guidance_scale, (int, float)) or guidance_scale < 1.0 or guidance_scale > 30.0:
                raise ContentValidationError("引导系数必须在1.0-30.0之间")
            validated["guidance_scale"] = float(guidance_scale)

        # 验证随机种子
        if "seed" in parameters:
            seed = parameters["seed"]
            if not isinstance(seed, int) or seed < 0 or seed > 2**32 - 1:
                raise ContentValidationError("随机种子必须在0-4294967295之间")
            validated["seed"] = seed

        return validated

    def _validate_video_parameters(self, parameters: Dict[str, Any]) -> Dict[str, Any]:
        """验证视频参数"""
        validated = {}

        # 验证时长
        if "duration" in parameters:
            duration = parameters["duration"]
            if not isinstance(duration, int) or duration < 1 or duration > 300:
                raise ContentValidationError("视频时长必须在1-300秒之间")
            validated["duration"] = duration

        # 验证帧率
        if "fps" in parameters:
            fps = parameters["fps"]
            if not isinstance(fps, (int, float)) or fps < 1.0 or fps > 60.0:
                raise ContentValidationError("帧率必须在1.0-60.0之间")
            validated["fps"] = float(fps)

        # 验证分辨率
        if "resolution" in parameters:
            resolution = parameters["resolution"]
            valid_resolutions = ["360p", "480p", "720p", "1080p", "2K", "4K"]
            if resolution not in valid_resolutions:
                raise ContentValidationError(f"无效的分辨率: {resolution}")
            validated["resolution"] = resolution

        return validated

    def _validate_audio_parameters(self, parameters: Dict[str, Any]) -> Dict[str, Any]:
        """验证音频参数"""
        validated = {}

        # 验证时长
        if "duration" in parameters:
            duration = parameters["duration"]
            if not isinstance(duration, int) or duration < 1 or duration > 3600:
                raise ContentValidationError("音频时长必须在1-3600秒之间")
            validated["duration"] = duration

        # 验证采样率
        if "sample_rate" in parameters:
            sample_rate = parameters["sample_rate"]
            valid_sample_rates = [8000, 16000, 22050, 44100, 48000]
            if sample_rate not in valid_sample_rates:
                raise ContentValidationError(f"无效的采样率: {sample_rate}")
            validated["sample_rate"] = sample_rate

        return validated

    def _validate_text_parameters(self, parameters: Dict[str, Any]) -> Dict[str, Any]:
        """验证文本参数"""
        validated = {}

        # 验证最大长度
        if "max_length" in parameters:
            max_length = parameters["max_length"]
            if not isinstance(max_length, int) or max_length < 1 or max_length > 10000:
                raise ContentValidationError("最大长度必须在1-10000字符之间")
            validated["max_length"] = max_length

        # 验证温度
        if "temperature" in parameters:
            temperature = parameters["temperature"]
            if not isinstance(temperature, (int, float)) or temperature < 0.0 or temperature > 2.0:
                raise ContentValidationError("温度必须在0.0-2.0之间")
            validated["temperature"] = float(temperature)

        return validated

    async def _submit_to_task_queue(
        self,
        session: AsyncSession,
        request: CreationRequest
    ) -> None:
        """提交到任务队列"""
        # 创建任务队列记录
        task = TaskQueue(
            user_id=request.user_id,
            related_request_id=request.id,
            task_type=TaskType.CONTENT_GENERATION,
            task_name=f"生成{request.content_type}内容",
            description=request.title or request.prompt[:100],
            task_id=str(uuid.uuid4()),
            priority=self._map_priority(request.priority),
            estimated_duration=self._estimate_duration(request.content_type),
            timeout_seconds=settings.content_generation.generation_timeout_seconds,
            task_parameters={
                "request_id": str(request.id),
                "content_type": request.content_type,
                "prompt": request.prompt,
                "negative_prompt": request.negative_prompt,
                "ai_provider": request.ai_provider,
                "ai_model": request.ai_model,
                "parameters": request.get_generation_config()
            }
        )

        session.add(task)
        request.task_id = task.task_id

        logger.info("内容生成请求已提交到任务队列", 
                   request_id=str(request.id), 
                   task_id=task.task_id)

    def _map_priority(self, priority: str) -> int:
        """映射优先级"""
        priority_map = {
            Priority.LOW: TaskPriority.LOW,
            Priority.NORMAL: TaskPriority.NORMAL,
            Priority.HIGH: TaskPriority.HIGH,
            Priority.URGENT: TaskPriority.URGENT,
        }
        return priority_map.get(priority, TaskPriority.NORMAL)

    def _estimate_duration(self, content_type: str) -> int:
        """估算任务执行时间（秒）"""
        duration_map = {
            "image": 30,      # 图片生成约30秒
            "video": 300,     # 视频生成约5分钟
            "audio": 120,     # 音频生成约2分钟
            "text": 10,       # 文本生成约10秒
        }
        return duration_map.get(content_type, 60)  # 默认1分钟